home *** CD-ROM | disk | FTP | other *** search
/ Aminet 49 / Aminet 49 (2002)(GTI - Schatztruhe)[!][Jun 2002].iso / Aminet / util / misc / ReportPlus.lha / ReportPlus / source / f8.c < prev    next >
C/C++ Source or Header  |  2002-04-15  |  77KB  |  2,136 lines

  1. #include <exec/types.h>
  2. #include <exec/memory.h>
  3. #include <proto/exec.h>
  4. #include <intuition/intuition.h>
  5. #include <intuition/gadgetclass.h>
  6. #include <proto/intuition.h>
  7. #include <libraries/gadtools.h>
  8. #include <proto/gadtools.h>
  9. #include <dos/dos.h>
  10. #include <dos/exall.h>
  11. #include <dos/dostags.h>
  12. #include <proto/dos.h>
  13. #include <graphics/gfx.h>
  14. #include <clib/graphics_protos.h>
  15. #include <clib/alib_protos.h>
  16. #include <libraries/asl.h>
  17. #include <clib/asl_protos.h>
  18.  
  19. #include <ctype.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "rp.h"
  23.  
  24. #define ALL_REACTION_CLASSES
  25. #include <reaction/reaction.h>
  26.  
  27. #define LIMIT_DIRS        8196
  28. #define MAX_FILES (128 * 1024)
  29. #define TRUNCATE            39
  30. #define GRANULARITY_DIRS    10
  31. #define GRANULARITY_FILES   10
  32.  
  33. /* Limitations:
  34.    LIMIT_DIRS (top-level list entries).
  35.    MAX_FILES (total files/dirs in path). */
  36.  
  37. MODULE void pop(void);
  38. MODULE void push(STRPTR name, ULONG theindex);
  39. MODULE void subdir(ULONG theindex);
  40. MODULE void parent(void);
  41. MODULE void root(void);
  42. MODULE void pathasl(void);
  43. MODULE void comma(ULONG value);
  44. MODULE ABOOL dirasl(void);
  45. MODULE void showduplicates(void);
  46. MODULE void addduplicate(STRPTR path, STRPTR filename);
  47. MODULE void writeline(void);
  48. MODULE void killduplist(void);
  49. MODULE void killsizelist(void);
  50. MODULE void ghost(void);
  51. MODULE void unghost(void);
  52. MODULE void scale(ULONG bytes);
  53. MODULE void __inline progressbar(ULONG level);
  54.  
  55. #define UNITOPTIONS 3 // counting from 0
  56. MODULE STRPTR UnitOptions[UNITOPTIONS + 1] =
  57. {   "Bytes",
  58.     "Kilobytes",
  59.     "Megabytes",
  60.     "Blocks"
  61. };
  62.  
  63. MODULE struct ColumnInfo SizeColumnInfo[] =
  64. { { 75,            // WORD   ci_Width
  65.     "Pathname",    // STRPTR ci_Title
  66.     0,             // ULONG  ci_Flags
  67.   },
  68.   { 25,
  69.     "Size",
  70.     0, /* Last column must not have CIF_DRAGGABLE set (CIF_DRAGGABLE applies
  71.           to the right border of the relevant column). */
  72.   },
  73.   { -1, (STRPTR) ~0, -1
  74. } },
  75. DupColumnInfo[] =
  76. { { 40,            // WORD   ci_Width
  77.     "Pathname",    // STRPTR ci_Title
  78.     0,             // ULONG  ci_Flags
  79.   },
  80.   { 10,
  81.     "Byte size",
  82.     0,
  83.   },
  84.   { 10,
  85.     "Date",
  86.     0,
  87.   },
  88.   { 10,
  89.     "Time",
  90.     0,
  91.   },
  92.   { 30,
  93.     "Version",
  94.     0, /* Last column must not have CIF_DRAGGABLE set (CIF_DRAGGABLE applies
  95.           to the right border of the relevant column). */
  96.   },
  97.   { -1, (STRPTR) ~0, -1
  98. } };
  99.  
  100. IMPORT SBYTE               page;
  101. IMPORT TEXT                globalname[VLONGFIELD + 1],
  102.                            weekdaystring[10],
  103.                            datestring[10],
  104.                            timestring[9],
  105.                            asldir[VLONGFIELD + 1],
  106.                            aslresult[MEDFIELD + 1],
  107.                            IOBuffer[LONGESTFIELD + 1];
  108. IMPORT struct NewGadget    Gadget;
  109. IMPORT struct SharedStruct shared;
  110. IMPORT struct Screen*      ScreenPtr;
  111. IMPORT struct Window*      MainWindowPtr;
  112. IMPORT struct ExAllData*   EADataPtr;
  113. IMPORT struct Menu*        MenuPtr;
  114. IMPORT Object*             WinObject[FUNCTIONS + 1];
  115. IMPORT ULONG               increment;
  116.  
  117. AGLOBAL struct Gadget*     size_gadgets[GIDS_8 + 1];
  118.  
  119. MODULE ABOOL               DupNodes       = FALSE,
  120.                            SizeNodes      = FALSE,
  121.                            EmptyDupNodes  = FALSE,
  122.                            EmptySizeNodes = FALSE,
  123.                            ram            = FALSE;
  124. MODULE struct List         SizeList,
  125.                            DupList,
  126.                            EmptySizeList,
  127.                            EmptyDupList;
  128. MODULE STRPTR*             PathnamePtr;
  129. MODULE STRPTR*             FilenamePtr;
  130. MODULE STRPTR*             StackPtr;
  131. MODULE STRPTR*             DirNamePtr;
  132. MODULE ABOOL*              IsDup;
  133. MODULE BPTR                TempHandle     = NULL,
  134.                            DirHandle      = NULL,
  135.                            LogFileHandle  = NULL;
  136. MODULE TEXT                logstring[VLONGFIELD + 1],
  137.                            liststring[5][VLONGFIELD + 1];
  138. MODULE UBYTE               valuestring[11],
  139.                            commastring[14],
  140.                            pathlength;
  141. MODULE ULONG               DirNamesAllocated  = 0,
  142.                            FileNamesAllocated = 0,
  143.                            files              = 0, // how many files have been found. Counting from 1.
  144.                            status             = STATUS_READY;
  145.  
  146. MODULE struct
  147. {   ULONG entries, total, free, capacity, stackentries, blocksize,
  148.           finddup, slack, bytes[LIMIT_DIRS], topdir[LIMIT_DIRS], view,
  149.           numfiles, numdirs, log;
  150.     LONG  type[LIMIT_DIRS];
  151.     TEXT  oldpath[VLONGFIELD + 1], path[VLONGFIELD + 1], logfile[VLONGFIELD + 1];
  152. } size;
  153.  
  154. AGLOBAL void size_init(void)
  155. {   struct Node* ListBrowserNodePtr;
  156.                                                                                 strcpy(size.path, "RAM:");
  157.     strcpy(size.logfile, "RAM:ReportPlus.txt");
  158.     size.finddup = size.slack = size.log = FALSE;
  159.     size.free = size.capacity = size.total = size.numfiles = size.numdirs = 0;
  160.  
  161.     NewList(&SizeList);
  162.     NewList(&EmptySizeList);
  163.     if (!(ListBrowserNodePtr = AllocListBrowserNode
  164.     (   2,                  // columns
  165.         /* LBNCA_ tags are those that apply to the specific column. */
  166.         LBNA_Column,        0,
  167.         LBNA_Column,        1,
  168.         TAG_END
  169.     )))
  170.     {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  171.     }
  172.     AddTail(&EmptySizeList, ListBrowserNodePtr); // AddTail() has no return code
  173.     EmptySizeNodes = TRUE;
  174.  
  175.     NewList(&DupList);
  176.     NewList(&EmptyDupList);
  177.     if (!(ListBrowserNodePtr = AllocListBrowserNode
  178.     (   5,                  // columns
  179.         /* LBNCA_ tags are those that apply to the specific column. */
  180.         LBNA_Column,        0,
  181.         LBNA_Column,        1,
  182.         LBNA_Column,        2,
  183.         LBNA_Column,        3,
  184.         LBNA_Column,        4,
  185.         TAG_END
  186.     )))
  187.     {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  188.     }
  189.     AddTail(&EmptyDupList, ListBrowserNodePtr); // AddTail() has no return code
  190.     EmptyDupNodes = TRUE;
  191. }
  192.  
  193. AGLOBAL void size1(void)
  194. {   struct Hook         Hook8Struct;
  195.     struct List         ChooserList;
  196.     struct ChooserNode* ChooserNodePtr[UNITOPTIONS + 1];
  197.     ULONG               i;
  198.     TEXT                freestring[13 + 1],
  199.                         totalstring[13 + 1],
  200.                         capacitystring[13 + 1],
  201.                         filesstring[9 + 1],
  202.                         dirsstring[9 + 1],
  203.                         blocksizestring[9 + 1];
  204.  
  205.     comma(size.numfiles);
  206.     strcpy(filesstring, commastring);
  207.     comma(size.numdirs);
  208.     strcpy(dirsstring, commastring);
  209.     comma(size.blocksize);
  210.     strcpy(blocksizestring, commastring);
  211.     scale(size.free);
  212.     strcpy(freestring, commastring);
  213.     scale(size.total);
  214.     strcpy(totalstring, commastring);
  215.     scale(size.capacity);
  216.     strcpy(capacitystring, commastring);
  217.  
  218.     NewList(&ChooserList);
  219.     for (i = 0; i <= UNITOPTIONS; i++)
  220.     {   if (!(ChooserNodePtr[i] = (struct ChooserNode *) AllocChooserNode(CNA_Text, UnitOptions[i], TAG_DONE)))
  221.         {   rq("Can't allocate chooser node!");
  222.         }
  223.         AddTail(&ChooserList, (struct Node *) ChooserNodePtr[i]);
  224.     } // automatically freed by ReAction at DisposeObject() time
  225.  
  226.     /* Create the window object. */
  227.     lockscreen();
  228.     gadtools();
  229.     InitHook(&Hook8Struct, Hook8Func, NULL);
  230.  
  231.     /* We can't just use EmptyList for an empty columnar list, we
  232.     actually need a node (with the LBNA_Column tags) to be present.
  233.  
  234.     LISTBROWSER_ScrollRaster seems not to be usable with
  235.     multi-column lists. */
  236.  
  237.     if (!(WinObject[8] =          NewObject(WINDOW_GetClass(), NULL,
  238.     // window
  239.     WA_PubScreen,                 ScreenPtr,
  240.     WA_ScreenTitle,               "Report+",
  241.     WA_Title,                     "Report+: Path Size Report",
  242.     WA_Activate,                  TRUE,
  243.     WA_DepthGadget,               TRUE,
  244.     WA_DragBar,                   TRUE,
  245.     WA_CloseGadget,               TRUE,
  246.     WA_SizeGadget,                TRUE,
  247.     WA_IDCMP,                     IDCMP_RAWKEY,
  248.     WINDOW_IDCMPHook,             &Hook8Struct,
  249.     WINDOW_IDCMPHookBits,         IDCMP_RAWKEY,
  250.     WINDOW_MenuStrip,             MenuPtr,
  251.     WINDOW_Position,              WPOS_FULLSCREEN,
  252.     WINDOW_ParentGroup,           size_gadgets[GID_8_LY1] =
  253.     NewObject
  254.     (       LAYOUT_GetClass(), NULL,
  255.             // root-layout
  256.             LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
  257.             LAYOUT_SpaceOuter,         TRUE,
  258.             LAYOUT_DeferLayout,        TRUE,
  259.             LAYOUT_AddChild,
  260.             NewObject
  261.             (   LAYOUT_GetClass(),     NULL,
  262.                 LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
  263.                 LAYOUT_SpaceOuter,     TRUE,
  264.                 LAYOUT_VertAlignment,  LALIGN_CENTER,
  265.                 LAYOUT_HorizAlignment, LALIGN_CENTER,
  266.                 LAYOUT_BevelStyle,     BVS_NONE,
  267.                 LAYOUT_AddImage,
  268.                 NewObject
  269.                 (   LABEL_GetClass(),  NULL,
  270.                     LABEL_Text,        "_Path:",
  271.                     LABEL_Justification,LJ_LEFT,
  272.                 TAG_END),
  273.                 CHILD_WeightedWidth,   0,
  274.                 LAYOUT_AddChild,       size_gadgets[GID_8_ST1] =
  275.                 NewObject
  276.                 (   STRING_GetClass(), NULL,
  277.                     GA_ID,             GID_8_ST1,
  278.                     GA_RelVerify,      TRUE,
  279.                     STRINGA_TextVal,   size.path,
  280.                     STRINGA_MinVisible,35,
  281.                 TAG_END),
  282.                 LAYOUT_AddChild,       size_gadgets[GID_8_BU1] =
  283.                 NewObject(NULL,        "button.gadget",
  284.                     GA_ID,             GID_8_BU1,
  285.                     GA_RelVerify,      TRUE,
  286.                     BUTTON_AutoButton, BAG_POPFILE,
  287.                 TAG_END),
  288.                 CHILD_WeightedWidth,   0,
  289.             TAG_END),
  290.             CHILD_WeightedHeight,      0,
  291.             LAYOUT_AddChild,           NewObject(LAYOUT_GetClass(), NULL,
  292.                 LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
  293.                 LAYOUT_SpaceOuter,     TRUE,
  294.                 LAYOUT_VertAlignment,  LALIGN_CENTER,
  295.                 LAYOUT_HorizAlignment, LALIGN_CENTER,
  296.                 LAYOUT_BevelStyle,     BVS_NONE,
  297.                 LAYOUT_ShrinkWrap,     TRUE,
  298.                 LAYOUT_AddChild,       size_gadgets[GID_8_CB1] =
  299.                 NewObject
  300.                 (   CHECKBOX_GetClass(),NULL,
  301.                     // checkbox
  302.                     GA_ID,             GID_8_CB1,
  303.                     GA_RelVerify,      TRUE,
  304.                     GA_Text,           "_Log to:",
  305.                     GA_Selected,       (BOOL) size.log,
  306.                     TAG_END
  307.                 ),
  308.                 CHILD_WeightedWidth,   0,
  309.                 LAYOUT_AddChild,       size_gadgets[GID_8_ST2] =
  310.                                        NewObject(STRING_GetClass(), NULL,
  311.                     // string        
  312.                     GA_ID,             GID_8_ST2,
  313.                     GA_RelVerify,      TRUE,
  314.                     STRINGA_TextVal,   size.logfile,
  315.                     STRINGA_MinVisible,20,
  316.                     GA_Disabled,       !size.log,
  317.                     TAG_END
  318.                 ),
  319.                 LAYOUT_AddChild,       size_gadgets[GID_8_BU3] =
  320.                 NewObject
  321.                 (   NULL,              "button.gadget",
  322.                     // button
  323.                     GA_ID,             GID_8_BU3,
  324.                     GA_RelVerify,      TRUE,
  325.                     BUTTON_AutoButton, BAG_POPFILE,
  326.                     GA_Disabled,       !size.log,
  327.                     TAG_END
  328.                 ),
  329.                 CHILD_WeightedWidth,   0,
  330.                 TAG_END
  331.             ),
  332.             CHILD_WeightedHeight,      0,
  333.             LAYOUT_AddChild,
  334.             NewObject
  335.             (   LAYOUT_GetClass(),     NULL,
  336.                 LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
  337.                 LAYOUT_SpaceOuter,     TRUE,
  338.                 LAYOUT_VertAlignment,  LALIGN_CENTER,
  339.                 LAYOUT_HorizAlignment, LALIGN_CENTER,
  340.                 LAYOUT_BevelStyle,     BVS_FIELD,
  341.                 LAYOUT_AddChild,
  342.                 NewObject
  343.                 (   LAYOUT_GetClass(),     NULL,
  344.                     LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
  345.                     LAYOUT_SpaceOuter,     TRUE,
  346.                     LAYOUT_VertAlignment,  LALIGN_CENTER,
  347.                     LAYOUT_HorizAlignment, LALIGN_CENTER,
  348.                     LAYOUT_BevelStyle,     BVS_NONE,
  349.                     LAYOUT_AddChild,       size_gadgets[GID_8_BU6] =
  350.                     NewObject
  351.                     (   NULL,              "button.gadget",
  352.                         GA_ID,             GID_8_BU6,
  353.                         GA_RelVerify,      TRUE,
  354.                         GA_Text,           "_Root",
  355.                         TAG_END
  356.                     ),
  357.                     CHILD_WeightedWidth,   50,
  358.                     LAYOUT_AddChild,       size_gadgets[GID_8_BU7] =
  359.                     NewObject             
  360.                     (   NULL,              "button.gadget",
  361.                         GA_ID,             GID_8_BU7,
  362.                         GA_RelVerify,      TRUE,
  363.                         GA_Text,           "P_arent",
  364.                         TAG_END
  365.                     ),
  366.                     CHILD_WeightedWidth,   50,
  367.                 TAG_END),
  368.                 CHILD_WeightedHeight,      0,
  369.                 LAYOUT_AddChild,           size_gadgets[GID_8_LB2] =
  370.                 NewObject
  371.                 (   LISTBROWSER_GetClass(),NULL,
  372.                     GA_ID,                 GID_8_LB2,
  373.                     GA_RelVerify,          TRUE,
  374.                     GA_TextAttr,           Gadget.ng_TextAttr,
  375.                     LISTBROWSER_Labels,    (ULONG) &EmptySizeList,
  376.                     LISTBROWSER_ColumnInfo,(ULONG) &SizeColumnInfo,
  377.                     LISTBROWSER_ColumnTitles,TRUE,
  378.                 TAG_END),
  379.                 CHILD_WeightedHeight,      100,
  380.                 LAYOUT_AddChild,
  381.                 NewObject
  382.                 (   LAYOUT_GetClass(),     NULL,
  383.                     LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
  384.                     LAYOUT_SpaceOuter,     TRUE,
  385.                     LAYOUT_VertAlignment,  LALIGN_LEFT,
  386.                     LAYOUT_HorizAlignment, LALIGN_RIGHT,
  387.                     LAYOUT_BevelStyle,     BVS_NONE,
  388.                     LAYOUT_AddChild,
  389.                     NewObject
  390.                     (   LAYOUT_GetClass(),     NULL,
  391.                         LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
  392.                         LAYOUT_SpaceOuter,     TRUE,
  393.                         LAYOUT_VertAlignment,  LALIGN_CENTER,
  394.                         LAYOUT_HorizAlignment, LALIGN_RIGHT,
  395.                         LAYOUT_BevelStyle,     BVS_NONE,
  396.                         LAYOUT_AddImage,
  397.                         NewObject
  398.                         (   LABEL_GetClass(),  NULL,
  399.                             LABEL_Text,        "Files:",
  400.                             LABEL_Justification,LJ_CENTRE,
  401.                         TAG_END),
  402.                         CHILD_WeightedHeight,  0,
  403.                         LAYOUT_AddImage,
  404.                         NewObject
  405.                         (   LABEL_GetClass(),  NULL,
  406.                             LABEL_Text,        "Directories:",
  407.                             LABEL_Justification,LJ_CENTRE,
  408.                         TAG_END),
  409.                         CHILD_WeightedHeight,  0,
  410.                         LAYOUT_AddImage,
  411.                         NewObject
  412.                         (   LABEL_GetClass(),  NULL,
  413.                             LABEL_Text,        "Block size:",
  414.                             LABEL_Justification,LJ_CENTRE,
  415.                         TAG_END),
  416.                         CHILD_WeightedHeight,  0,
  417.                     TAG_END),
  418.                     CHILD_WeightedWidth,       0,
  419.                     LAYOUT_AddChild,
  420.                     NewObject
  421.                     (   LAYOUT_GetClass(),     NULL,
  422.                         LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
  423.                         LAYOUT_SpaceOuter,     TRUE,
  424.                         LAYOUT_VertAlignment,  LALIGN_CENTER,
  425.                         LAYOUT_HorizAlignment, LALIGN_RIGHT,
  426.                         LAYOUT_BevelStyle,     BVS_NONE,
  427.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST6] =
  428.                         NewObject
  429.                         (   STRING_GetClass(), NULL,
  430.                             GA_ID,             GID_8_ST6,
  431.                             GA_ReadOnly,       TRUE,
  432.                             STRINGA_TextVal,   filesstring,
  433.                             STRINGA_MinVisible,13,
  434.                             STRINGA_Justification,GACT_STRINGRIGHT,
  435.                             GA_TextAttr,       Gadget.ng_TextAttr,
  436.                         TAG_END),
  437.                         CHILD_WeightedHeight,  0,
  438.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST7] =
  439.                         NewObject
  440.                         (   STRING_GetClass(), NULL,
  441.                             GA_ID,             GID_8_ST7,
  442.                             GA_ReadOnly,       TRUE,
  443.                             STRINGA_TextVal,   dirsstring,
  444.                             STRINGA_MinVisible,13,
  445.                             STRINGA_Justification,GACT_STRINGRIGHT,
  446.                             GA_TextAttr,       Gadget.ng_TextAttr,
  447.                         TAG_END),
  448.                         CHILD_WeightedHeight,  0,
  449.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST8] =
  450.                         NewObject
  451.                         (   STRING_GetClass(), NULL,
  452.                             GA_ID,             GID_8_ST8,
  453.                             GA_ReadOnly,       TRUE,
  454.                             STRINGA_TextVal,   blocksizestring,
  455.                             STRINGA_MinVisible,13,
  456.                             STRINGA_Justification,GACT_STRINGRIGHT,
  457.                             GA_TextAttr,       Gadget.ng_TextAttr,
  458.                         TAG_END),
  459.                         CHILD_WeightedHeight,  0,
  460.                     TAG_END),
  461.                     CHILD_WeightedWidth,       0,
  462.                     LAYOUT_AddImage,           NewObject
  463.                     (   LABEL_GetClass(),      NULL,
  464.                         LABEL_Text,            "",
  465.                         TAG_END
  466.                     ),
  467.                     CHILD_WeightedWidth,       100,
  468.                     LAYOUT_AddChild,
  469.                     NewObject
  470.                     (   LAYOUT_GetClass(),     NULL,
  471.                         LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
  472.                         LAYOUT_SpaceOuter,     TRUE,
  473.                         LAYOUT_VertAlignment,  LALIGN_CENTER,
  474.                         LAYOUT_HorizAlignment, LALIGN_RIGHT,
  475.                         LAYOUT_BevelStyle,     BVS_NONE,
  476.                         LAYOUT_AddImage,
  477.                         NewObject
  478.                         (   LABEL_GetClass(),  NULL,
  479.                             LABEL_Text,        "Used in path:",
  480.                             LABEL_Justification,LJ_RIGHT,
  481.                         TAG_END),
  482.                         CHILD_WeightedHeight,  0,
  483.                         LAYOUT_AddImage,
  484.                         NewObject
  485.                         (   LABEL_GetClass(),  NULL,
  486.                             LABEL_Text,        "Free on volume:",
  487.                             LABEL_Justification,LJ_RIGHT,
  488.                         TAG_END),
  489.                         CHILD_WeightedHeight,  0,
  490.                         LAYOUT_AddImage,
  491.                         NewObject
  492.                         (   LABEL_GetClass(),  NULL,
  493.                             LABEL_Text,        "Volume capacity:",
  494.                             LABEL_Justification,LJ_RIGHT,
  495.                         TAG_END),
  496.                         CHILD_WeightedHeight,  0,
  497.                     TAG_END),
  498.                     CHILD_WeightedWidth,       0,
  499.                     LAYOUT_AddChild,
  500.                     NewObject
  501.                     (   LAYOUT_GetClass(),     NULL,
  502.                         LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
  503.                         LAYOUT_SpaceOuter,     TRUE,
  504.                         LAYOUT_VertAlignment,  LALIGN_CENTER,
  505.                         LAYOUT_HorizAlignment, LALIGN_RIGHT,
  506.                         LAYOUT_BevelStyle,     BVS_NONE,
  507.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST4] =
  508.                         NewObject
  509.                         (   STRING_GetClass(), NULL,
  510.                             GA_ID,             GID_8_ST4,
  511.                             GA_ReadOnly,       TRUE,
  512.                             STRINGA_TextVal,   totalstring,
  513.                             STRINGA_MinVisible,13,
  514.                             STRINGA_Justification,GACT_STRINGRIGHT,
  515.                             GA_TextAttr,       Gadget.ng_TextAttr,
  516.                         TAG_END),
  517.                         CHILD_WeightedHeight,  0,
  518.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST5] =
  519.                         NewObject
  520.                         (   STRING_GetClass(), NULL,
  521.                             GA_ID,             GID_8_ST5,
  522.                             GA_ReadOnly,       TRUE,
  523.                             STRINGA_TextVal,   freestring,
  524.                             STRINGA_MinVisible,13,
  525.                             STRINGA_Justification,GACT_STRINGRIGHT,
  526.                             GA_TextAttr,       Gadget.ng_TextAttr,
  527.                         TAG_END),
  528.                         CHILD_WeightedHeight,  0,
  529.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST3] =
  530.                         NewObject
  531.                         (   STRING_GetClass(), NULL,
  532.                             GA_ID,             GID_8_ST3,
  533.                             GA_ReadOnly,       TRUE,
  534.                             STRINGA_TextVal,   capacitystring,
  535.                             STRINGA_MinVisible,13,
  536.                             STRINGA_Justification,GACT_STRINGRIGHT,
  537.                             GA_TextAttr,       Gadget.ng_TextAttr,
  538.                         TAG_END),
  539.                         CHILD_WeightedHeight,  0,
  540.                     TAG_END),
  541.                     CHILD_WeightedWidth,       0,
  542.                 TAG_END),
  543.                 CHILD_WeightedHeight,          0,
  544.             TAG_END),
  545.             CHILD_WeightedHeight,              70,
  546.             LAYOUT_AddChild,
  547.             NewObject
  548.             (   LAYOUT_GetClass(),     NULL,
  549.                 LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
  550.                 LAYOUT_SpaceOuter,     TRUE,
  551.                 LAYOUT_VertAlignment,  LALIGN_CENTER,
  552.                 LAYOUT_HorizAlignment, LALIGN_CENTER,
  553.                 LAYOUT_BevelStyle,     BVS_NONE,
  554.                 LAYOUT_AddImage,
  555.                 NewObject
  556.                 (   LABEL_GetClass(),  NULL,
  557.                     // label
  558.                     LABEL_Text,        "_View as:",
  559.                     LABEL_Justification,LJ_RIGHT,
  560.                 TAG_END),
  561.                 CHILD_WeightedWidth,   0,
  562.                 LAYOUT_AddChild,       size_gadgets[GID_8_CH1] =
  563.                 NewObject
  564.                 (   CHOOSER_GetClass(),NULL,
  565.                     GA_ID,             GID_8_CH1,
  566.                     GA_RelVerify,      TRUE,
  567.                     CHOOSER_PopUp,     TRUE,
  568.                     CHOOSER_Labels,    &ChooserList,
  569.                     CHOOSER_Selected,  size.view,
  570.                     TAG_END
  571.                 ),
  572.                 CHILD_WeightedWidth,   0,
  573.                 LAYOUT_AddImage,       NewObject
  574.                 (   LABEL_GetClass(),  NULL,
  575.                     LABEL_Text,        "",
  576.                     TAG_END
  577.                 ),
  578.                 CHILD_WeightedWidth,   100,
  579.                 LAYOUT_AddChild,       size_gadgets[GID_8_CB2] =
  580.                 NewObject
  581.                 (   CHECKBOX_GetClass(),NULL,
  582.                     // checkbox
  583.                     GA_ID,             GID_8_CB2,
  584.                     GA_RelVerify,      TRUE,
  585.                     GA_Text,           "Include _slack?",
  586.                     GA_Selected,       (BOOL) size.slack,
  587.                 TAG_END),
  588.                 CHILD_WeightedWidth,   0,
  589.                 LAYOUT_AddChild,       size_gadgets[GID_8_CB3] =
  590.                 NewObject
  591.                 (   CHECKBOX_GetClass(),NULL,
  592.                     // checkbox
  593.                     GA_ID,             GID_8_CB3,
  594.                     GA_RelVerify,      TRUE,
  595.                     GA_Text,           "Find _duplicates?",
  596.                     GA_Selected,       (BOOL) size.finddup,
  597.                     TAG_END
  598.                 ),
  599.                 CHILD_WeightedWidth,   0,
  600.             TAG_END),
  601.             CHILD_WeightedHeight,     0,
  602.             LAYOUT_AddChild,          size_gadgets[GID_8_LB1] =
  603.             NewObject
  604.             (   LISTBROWSER_GetClass(),NULL,
  605.                 GA_ID,                GID_8_LB1,
  606.                 GA_ReadOnly,          TRUE,
  607.                 GA_TextAttr,          Gadget.ng_TextAttr,
  608.                 GA_Disabled,          !size.finddup,
  609.                 LISTBROWSER_Labels,   (ULONG) &EmptyDupList,
  610.                 LISTBROWSER_ColumnInfo,(ULONG) &DupColumnInfo,
  611.                 LISTBROWSER_ColumnTitles,TRUE,
  612.                 LISTBROWSER_HorizontalProp,TRUE,
  613.                 LISTBROWSER_VirtualWidth,620 + 155,
  614.             TAG_END),
  615.             CHILD_WeightedHeight,     30,
  616.             LAYOUT_AddChild,          size_gadgets[GID_8_FG1] =
  617.             NewObject
  618.             (   FUELGAUGE_GetClass(), NULL,
  619.                 GA_ID,                GID_8_FG1,
  620.                 GA_Text,              "Ready.",
  621.                 FUELGAUGE_Level,      0,
  622.                 FUELGAUGE_Percent,    FALSE,
  623.                 FUELGAUGE_Justification,FGJ_CENTER,
  624.             TAG_END),
  625.             CHILD_WeightedHeight,     0,
  626.             LAYOUT_AddChild,
  627.             NewObject
  628.             (   LAYOUT_GetClass(),    NULL,
  629.                 LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
  630.                 LAYOUT_SpaceOuter,    TRUE,
  631.                 LAYOUT_VertAlignment, LALIGN_CENTER,
  632.                 LAYOUT_HorizAlignment,LALIGN_CENTER,
  633.                 LAYOUT_BevelStyle,    BVS_NONE,
  634.                 LAYOUT_AddChild,      size_gadgets[GID_8_BU4] =
  635.                 NewObject
  636.                 (   NULL,             "button.gadget",
  637.                     GA_ID,            GID_8_BU4,
  638.                     GA_RelVerify,     TRUE,
  639.                     GA_Text,          "_Update",
  640.                 TAG_END),
  641.                 LAYOUT_AddChild,      size_gadgets[GID_8_BU5] =
  642.                 NewObject
  643.                 (   NULL,             "button.gadget",
  644.                     GA_ID,            GID_8_BU5,
  645.                     GA_RelVerify,     TRUE,
  646.                     GA_Text,          "Stop",
  647.                     GA_Disabled,      TRUE,
  648.                 TAG_END),
  649.             TAG_END),
  650.             CHILD_WeightedHeight,     0,
  651.     TAG_END)
  652.     )))
  653.     {   rq("Can't create ReAction objects!");
  654.     }
  655.     unlockscreen();
  656.     openwindow();
  657.     ActivateLayoutGadget(size_gadgets[GID_8_LY1], MainWindowPtr, NULL, (Object) size_gadgets[GID_8_ST1]);
  658.  
  659.     loop();
  660.     closewindow();
  661.     size_exit();
  662. }
  663.  
  664. AGLOBAL void updatesize(void)
  665. {   BOOL                  more; // note that it is BOOL, not ABOOL
  666.     TEXT                  tempstring[VLONGFIELD + 1],
  667.                           tempname[LONGFIELD + 1];
  668.     ULONG                 i, j, tempbytes, where;
  669.     LONG                  length, temptype; // these both MUST be signed
  670.     ABOOL                 failed      = FALSE;
  671.     struct FileInfoBlock* FIBPtr      = NULL;
  672.     struct InfoData*      InfoDataPtr;
  673.     struct ExAllControl*  eac;
  674.     struct ExAllData*     ead;
  675.     struct Node*          ListBrowserNodePtr;
  676.  
  677. /* 0: Ready
  678.    1: Reading directory...
  679.  ! 2: Reading subdirectories...
  680.    3: Sorting contents...
  681.  ![4: Matching duplicates...
  682.   [5: Condensing duplicates...
  683.   [6: Sorting duplicates...
  684.  ![7: Examining duplicates...
  685.  
  686. [ = only for duplicates
  687. ! = can be aborted by user
  688.  */
  689.  
  690.     if (SizeNodes)
  691.     {   clearlist(&SizeList);
  692.         SizeNodes = FALSE;
  693.     }
  694.     if (!DirNamePtr)
  695.     {   if (!(DirNamePtr = AllocVec(LIMIT_DIRS * sizeof(STRPTR), NULL)))
  696.         {   rq("Out of memory!");
  697.     }   }
  698.  
  699.     // 1: Ghost relevant gadgets, for duration of the operation.
  700.  
  701.     ghost();
  702.     SetGadgetAttrs
  703.     (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  704.         FUELGAUGE_Min,   0,
  705.         FUELGAUGE_Max,   100,
  706.         FUELGAUGE_Level, 25,
  707.         GA_Text,         "Reading directory...",
  708.         TAG_END
  709.     ); // we don't know how many files in advance...
  710.  
  711.     // 2: Now get a Lock() on the path.
  712.  
  713.     size.stackentries = size.entries = size.numdirs = size.numfiles = 0;
  714.     /* From RKRM I&A, p. 65: */
  715.     if
  716.     (   !(DirHandle = (BPTR) Lock(size.path, ACCESS_READ))
  717.      || !(FIBPtr    = AllocDosObject(DOS_FIB, NULL))
  718.      || !(            Examine(DirHandle, FIBPtr))
  719.      ||  (FIBPtr->fib_DirEntryType <= 0) // if not a directory
  720.     )
  721.     {   failed = TRUE;
  722.     }
  723.  
  724.     strcpy(size.oldpath, size.path);
  725.     if (FIBPtr)
  726.     {   FreeDosObject(DOS_FIB, FIBPtr);
  727.         // FIBPtr = NULL;
  728.     }
  729.     if (failed)
  730.     {   DisplayBeep(ScreenPtr);
  731.         unghost();
  732.  
  733.         strcpy(size.path, size.oldpath);
  734.         SetGadgetAttrs
  735.         (   size_gadgets[GID_8_ST1], MainWindowPtr, NULL,
  736.             STRINGA_TextVal, size.path,
  737.             TAG_END
  738.         );
  739.         SetGadgetAttrs
  740.         (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  741.             FUELGAUGE_Level, 0,
  742.             GA_Text,         "Failed!",
  743.             TAG_END
  744.         );
  745.         return;
  746.     }
  747.     SetGadgetAttrs
  748.     (   size_gadgets[GID_8_ST1], MainWindowPtr, NULL,
  749.         STRINGA_TextVal, size.path,
  750.         TAG_END
  751.     );
  752.  
  753.     /* 3: Now we call Info() to ascertain the free bytes.
  754.           InfoDataPtr must be longword-aligned. */
  755.  
  756.     if (!(InfoDataPtr = AllocVec(sizeof(struct InfoData), MEMF_CLEAR)))
  757.     {   rq("Out of memory!");
  758.     }
  759.     if (Info(DirHandle, InfoDataPtr))
  760.     {   size.blocksize = InfoDataPtr->id_BytesPerBlock;
  761.         size.free      =
  762.         (InfoDataPtr->id_NumBlocks - InfoDataPtr->id_NumBlocksUsed) *
  763.          InfoDataPtr->id_BytesPerBlock;
  764.         size.capacity  =
  765.          InfoDataPtr->id_NumBlocks *
  766.          InfoDataPtr->id_BytesPerBlock;
  767.     } else
  768.     {   rq("Can't get volume info!");
  769.     }
  770.     FreeVec(InfoDataPtr);
  771.     // InfoDataPtr = NULL;
  772.  
  773.     comma(size.blocksize);
  774.     SetGadgetAttrs // "dirs"
  775.     (   size_gadgets[GID_8_ST8], MainWindowPtr, NULL,
  776.         STRINGA_TextVal, commastring,
  777.         TAG_END
  778.     );
  779.  
  780.     /* 4: Now we are ready to begin the main part of the operation.
  781.  
  782.     size.topdir[]     = the 'owning' top-level directory for this subdir.
  783.                         Top-level dirs are owned by themselves.
  784.     size.bytes[]      = the size of this top-level directory/file.
  785.     size.entries      = how many top-level dirs, ie. how many names in the
  786.                         listview gadget.
  787.     size.path         = the path (drive, partition, etc.) the user is doing
  788.                         the report on.
  789.     size.stackentries = the current size of the stack.
  790.     DirNamesAllocated = the number of allocated chunks for the
  791.                         topdir names. */
  792.  
  793.     if (!(        StackPtr = AllocVec(LIMIT_DIRS * sizeof(STRPTR), NULL)))
  794.     {   rq("Out of memory!");
  795.     }
  796.  
  797.     files = size.total = 0;
  798.     if (size.finddup)
  799.     {   if (!( PathnamePtr = AllocVec(MAX_FILES * sizeof(STRPTR), NULL)))
  800.         {   rq("Out of memory!");
  801.         }
  802.         if (!( FilenamePtr = AllocVec(MAX_FILES * sizeof(STRPTR), NULL)))
  803.         {   rq("Out of memory!");
  804.         }
  805.         if (!(       IsDup = AllocVec(MAX_FILES * sizeof(ABOOL) , NULL)))
  806.         {   rq("Out of memory!");
  807.     }   }
  808.  
  809.     // This must be allocated with AllocDosObject()
  810.     if (!(eac = AllocDosObject(DOS_EXALLCONTROL, NULL)))
  811.     {   rq("Can't allocate DOS object!");
  812.     }
  813.  
  814.     eac->eac_LastKey = 0;
  815.     do
  816.     {   more = ExAll(DirHandle, (struct ExAllData *) EADataPtr, 4096, ED_SIZE, eac);
  817.         if (!more && IoErr() != ERROR_NO_MORE_ENTRIES)
  818.         {   FreeDosObject(DOS_EXALLCONTROL, eac);
  819.             eac = NULL;
  820.             rq("Can't examine path!");
  821.         }
  822.         if (eac->eac_Entries == 0)
  823.         {   ; /* ExAll() failed normally with no entries */
  824.             continue; /* more is USUALLY zero */
  825.         }
  826.  
  827.         // OK, ExAll() has generated up to 2K of data.
  828.         ead = (struct ExAllData *) EADataPtr;
  829.         do
  830.         {   /* use ead here */
  831.  
  832.             if (ead->ed_Type == -3 || ead->ed_Type == 2) // if a normal file or normal directory (ie. not a link)
  833.             {   size.entries++;
  834.                 if (size.entries == LIMIT_DIRS)
  835.                 {   FreeDosObject(DOS_EXALLCONTROL, eac);
  836.                     eac = NULL;
  837.                     rq("Overflow!");
  838.                 }
  839.                 size.type[size.entries] = ead->ed_Type;
  840.                 if (size.entries > DirNamesAllocated)
  841.                 {   if (!(DirNamePtr[DirNamesAllocated + 1] = AllocMem(VLONGFIELD, MEMF_PUBLIC)))
  842.                     {   FreeDosObject(DOS_EXALLCONTROL, eac);
  843.                         eac = NULL;
  844.                         rq("Out of memory!");
  845.                     }
  846.                     DirNamesAllocated++;
  847.                 }
  848.                 strcpy(DirNamePtr[size.entries], ead->ed_Name);
  849.                 if (ead->ed_Type == 2) /* +2 is dir, +3 is softlink, -3 is file */
  850.                 {   size.numdirs++;
  851.                     if (!(size.numdirs % GRANULARITY_DIRS))
  852.                     {   comma(size.numdirs);
  853.                         SetGadgetAttrs
  854.                         (   size_gadgets[GID_8_ST7], MainWindowPtr, NULL,
  855.                             STRINGA_TextVal, commastring,
  856.                             TAG_END
  857.                         );
  858.                     }
  859.                     size.bytes[size.entries] = 0;
  860.                     strcpy(tempstring, size.path);
  861.                     if (!AddPart(tempstring, ead->ed_Name, VLONGFIELD))
  862.                     {   FreeDosObject(DOS_EXALLCONTROL, eac);
  863.                         eac = NULL;
  864.                         rq("Can't add filename to pathname!");
  865.                     }
  866.                     push(tempstring, size.entries);
  867.                 } else
  868.                 {   size.numfiles++;
  869.                     if (!(size.numfiles % GRANULARITY_FILES))
  870.                     {   comma(size.numfiles);
  871.                         SetGadgetAttrs
  872.                         (   size_gadgets[GID_8_ST6], MainWindowPtr, NULL,
  873.                             STRINGA_TextVal, commastring,
  874.                             TAG_END
  875.                         );
  876.                     }
  877.                     addduplicate("", ead->ed_Name);
  878.                     if (size.slack)
  879.                     {   if (ead->ed_Size % size.blocksize == 0)
  880.                         {   size.bytes[size.entries] = (ead->ed_Size / size.blocksize) * size.blocksize;
  881.                             size.total              += (ead->ed_Size / size.blocksize) * size.blocksize;
  882.                         } else
  883.                         {   size.bytes[size.entries] = ((ead->ed_Size / size.blocksize) + 1) * size.blocksize;
  884.                             size.total              += ((ead->ed_Size / size.blocksize) + 1) * size.blocksize;
  885.                     }   }
  886.                     else
  887.                     {   size.bytes[size.entries]     = ead->ed_Size;
  888.                         size.total                  += ead->ed_Size;
  889.             }   }   }
  890.  
  891.             /* get next ead */
  892.             ead = ead->ed_Next;
  893.         } while(ead);
  894.     } while(more);
  895.  
  896.     FreeDosObject(DOS_EXALLCONTROL, eac);
  897.     // eac = NULL;
  898.     UnLock(DirHandle);
  899.     DirHandle = NULL;
  900.  
  901.     SetGadgetAttrs
  902.     (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  903.         FUELGAUGE_Min,   0,
  904.         FUELGAUGE_Max,   100,
  905.         FUELGAUGE_Level, 50,
  906.         GA_Text,         "Reading subdirectories...",
  907.         TAG_END
  908.     );
  909.     pop();
  910.  
  911.     // Now handle the list.
  912.     killsizelist();
  913.     if (status == STATUS_BUSY)
  914.     {   /* size.entries is the actual number of entries. The array elements are
  915.         from 1 to size.entries.
  916.  
  917.         bubble sort routine */
  918.  
  919.         SetGadgetAttrs
  920.         (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  921.             FUELGAUGE_Min,   0,
  922.             FUELGAUGE_Max,   size.entries - 2,
  923.             GA_Text,         "Sorting contents...",
  924.             TAG_END
  925.         );
  926.         setbar(size.entries - 2);
  927.  
  928.         for (i = size.entries; i >= 2; i--)
  929.         {   progressbar(size.entries - 1);
  930.  
  931.             for (j = 2; j <= i; j++)
  932.             {   if (size.bytes[j - 1] < size.bytes[j]) 
  933.                 {   // swap them
  934.                     tempbytes = size.bytes[j - 1];
  935.                     size.bytes[j - 1] = size.bytes[j]; 
  936.                     size.bytes[j] = tempbytes;
  937.                     temptype = size.type[j - 1];
  938.                     size.type[j - 1] = size.type[j];
  939.                     size.type[j] = temptype;
  940.                     strcpy(tempname, DirNamePtr[j - 1]);
  941.                     strcpy(DirNamePtr[j - 1], DirNamePtr[j]);
  942.                     strcpy(DirNamePtr[j], tempname);
  943.         }   }   }
  944.  
  945.         getdate();
  946.         if (size.log)
  947.         {   strcpy(logstring, "Path: \"");
  948.             strcat(logstring, size.path);
  949.             strcat(logstring, "\" at ");
  950.             strcat(logstring, timestring);
  951.             strcat(logstring, " on ");
  952.             strcat(logstring, weekdaystring);
  953.             strcat(logstring, " ");
  954.             strcat(logstring, datestring);
  955.             strcat(logstring, ":\n");
  956.             if (!(LogFileHandle = (BPTR) Open(size.logfile, MODE_READWRITE)))
  957.                 rq("Can't open file for appending!");
  958.             Seek(LogFileHandle, 0, OFFSET_END);
  959.             writeline();
  960.         }
  961.  
  962.         for (i = 1; i <= size.entries; i++)
  963.         {   scale(size.bytes[i]);
  964.  
  965.             if (size.log)
  966.             {   if (size.type[i] == 2)
  967.                 {   strcpy(logstring, "*");
  968.                 } else
  969.                 {   strcpy(logstring, " ");
  970.                 }
  971.                 strncat(logstring, DirNamePtr[i], TRUNCATE);
  972.                 if (strlen(DirNamePtr[i]) < TRUNCATE)
  973.                 {   length = TRUNCATE - strlen(DirNamePtr[i]);
  974.                     for (j = 1; j <= length; j++)
  975.                     {   strcat(logstring, " ");
  976.                 }   }
  977.                 strcat(logstring, " ");
  978.                 strcat(logstring, commastring);
  979.                 strcat(logstring, "\n");
  980.                 writeline();
  981.             }
  982.  
  983.             if (size.type[i] == 2)
  984.             {   strcpy(liststring[0], "*");
  985.             } else
  986.             {   strcpy(liststring[0], " ");
  987.             }
  988.             strcat(liststring[0], DirNamePtr[i]);
  989.             for (j = 0; j <= 13; j++)
  990.             {   if (commastring[j] != ' ')
  991.                 {   where = j; // where is index of first non-space character
  992.                     break;
  993.             }   }
  994.             strcpy(liststring[1], &commastring[where]);
  995.  
  996.             if (!(ListBrowserNodePtr = AllocListBrowserNode
  997.             (   2,                       // columns,
  998.                 LBNA_Column,             0,
  999.                     LBNCA_CopyText,      TRUE,
  1000.                     LBNCA_Text,          liststring[0],
  1001.                 LBNA_Column,             1,
  1002.                     LBNCA_CopyText,      TRUE,
  1003.                     LBNCA_Text,          &commastring[where],
  1004.                     LBNCA_Justification, LCJ_RIGHT,
  1005.                 TAG_END
  1006.             )))
  1007.             {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  1008.             }
  1009.  
  1010.             AddTail(&SizeList, ListBrowserNodePtr); // AddTail() has no return code
  1011.             SizeNodes = TRUE;
  1012.         }
  1013.  
  1014.         scale(size.total);
  1015.         SetGadgetAttrs // "used in path"
  1016.         (   size_gadgets[GID_8_ST4], MainWindowPtr, NULL,
  1017.             STRINGA_TextVal, commastring,
  1018.             TAG_END
  1019.         );
  1020.         scale(size.free);
  1021.         SetGadgetAttrs // "free on volume"
  1022.         (   size_gadgets[GID_8_ST5], MainWindowPtr, NULL,
  1023.             STRINGA_TextVal, commastring,
  1024.             TAG_END
  1025.         );
  1026.         scale(size.capacity);
  1027.         SetGadgetAttrs // "volume capacity"
  1028.         (   size_gadgets[GID_8_ST3], MainWindowPtr, NULL,
  1029.             STRINGA_TextVal, commastring,
  1030.             TAG_END
  1031.         );
  1032.         comma(size.numfiles);
  1033.         SetGadgetAttrs // "files"
  1034.         (   size_gadgets[GID_8_ST6], MainWindowPtr, NULL,
  1035.             STRINGA_TextVal, commastring,
  1036.             TAG_END
  1037.         );
  1038.         comma(size.numdirs);
  1039.         SetGadgetAttrs // "dirs"
  1040.         (   size_gadgets[GID_8_ST7], MainWindowPtr, NULL,
  1041.             STRINGA_TextVal, commastring,
  1042.             TAG_END
  1043.         );
  1044.  
  1045.         if (size.log)
  1046.         {   strcpy(logstring, "\nUsed in path:                            ");
  1047.             scale(size.total);
  1048.             strcat(logstring, commastring);
  1049.             strcat(logstring, "\nFree on volume:                          "); // these must be adjusted according to TRUNCATE
  1050.             scale(size.free);
  1051.             strcat(logstring, commastring);
  1052.             strcat(logstring, "\nVolume capacity:                         "); // these must be adjusted according to TRUNCATE
  1053.             scale(size.capacity);
  1054.             strcat(logstring, commastring);
  1055.             strcat(logstring, "\nFiles:                                   "); // these must be adjusted according to TRUNCATE
  1056.             comma(size.numfiles);
  1057.             strcat(logstring, commastring);
  1058.             strcat(logstring, "\nDirectories:                             "); // these must be adjusted according to TRUNCATE
  1059.             comma(size.numdirs);
  1060.             strcat(logstring, commastring);
  1061.             strcat(logstring, "\nBlock size:                              "); // these must be adjusted according to TRUNCATE
  1062.             comma(size.blocksize);
  1063.             strcat(logstring, commastring);
  1064.             strcat(logstring, "\n\n");
  1065.             writeline();
  1066.         }
  1067.  
  1068.         SetGadgetAttrs
  1069.         (   size_gadgets[GID_8_LB2], MainWindowPtr, NULL,
  1070.             LISTBROWSER_Labels, &SizeList,
  1071.             TAG_END
  1072.         );
  1073.         showduplicates();
  1074.     } else
  1075.     {   SetGadgetAttrs // "used in path"
  1076.         (   size_gadgets[GID_8_ST4], MainWindowPtr, NULL,
  1077.             STRINGA_TextVal, "-",
  1078.             TAG_END
  1079.         );
  1080.         SetGadgetAttrs // "free on volume"
  1081.         (   size_gadgets[GID_8_ST5], MainWindowPtr, NULL,
  1082.             STRINGA_TextVal, "-",
  1083.             TAG_END
  1084.         );
  1085.         SetGadgetAttrs // "volume capacity"
  1086.         (   size_gadgets[GID_8_ST3], MainWindowPtr, NULL,
  1087.             STRINGA_TextVal, "-",
  1088.             TAG_END
  1089.         );
  1090.         SetGadgetAttrs // "files"
  1091.         (   size_gadgets[GID_8_ST6], MainWindowPtr, NULL,
  1092.             STRINGA_TextVal, "-",
  1093.             TAG_END
  1094.         );
  1095.         SetGadgetAttrs // "directories"
  1096.         (   size_gadgets[GID_8_ST7], MainWindowPtr, NULL,
  1097.             STRINGA_TextVal, "-",
  1098.             TAG_END
  1099.         );
  1100.         SetGadgetAttrs // "block size"
  1101.         (   size_gadgets[GID_8_ST8], MainWindowPtr, NULL,
  1102.             STRINGA_TextVal, "-",
  1103.             TAG_END
  1104.         );
  1105.         killsizelist();
  1106.         killduplist();
  1107.     }
  1108.  
  1109.     unghost();
  1110.     SetGadgetAttrs
  1111.     (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1112.         FUELGAUGE_Min,     0,
  1113.         FUELGAUGE_Max,   100,
  1114.         FUELGAUGE_Level, 100,
  1115.         GA_Text,         "Done",
  1116.         TAG_END
  1117.     );
  1118.  
  1119.     if (LogFileHandle)
  1120.     {   Close(LogFileHandle);
  1121.         LogFileHandle = NULL;
  1122.     }
  1123.     while (FileNamesAllocated)
  1124.     {   FreeMem(StackPtr[FileNamesAllocated], VLONGFIELD);
  1125.         StackPtr[FileNamesAllocated--] = NULL;
  1126.     }
  1127.     FreeVec(StackPtr);
  1128.     StackPtr = NULL;
  1129.  
  1130.     // We need the DirNamePtr[] array to remain valid, because
  1131.     // the user can click on the listview gadget.
  1132. }
  1133.  
  1134. MODULE void subdir(ULONG topdir)
  1135. {   BOOL                 more;
  1136.     TEXT                 tempstring[VLONGFIELD + 1];
  1137.     struct ExAllControl* eac;
  1138.     struct ExAllData*    ead;
  1139.  
  1140.     /* Instead of passing a pointer to the path, we use a global string.
  1141.     There are memory corruption problems if you pass pointers to variables
  1142.     which are really local to other functions.
  1143.  
  1144.     This is dynamically allocated as it must be at least word-aligned;
  1145.     also remember not to allocate large arrays on the stack. */
  1146.  
  1147.     if (!(DirHandle = (BPTR) Lock(globalname, ACCESS_READ)))
  1148.     {   DisplayBeep(ScreenPtr);
  1149.         return;
  1150.     }
  1151.     if (!(eac = AllocDosObject(DOS_EXALLCONTROL, NULL)))
  1152.     {   UnLock(DirHandle);
  1153.         DirHandle = NULL;
  1154.         rq("Can't allocate DOS object!");
  1155.     }
  1156.  
  1157.     eac->eac_LastKey = 0;
  1158.     do
  1159.     {   more = ExAll(DirHandle, (struct ExAllData *) EADataPtr, 4096, ED_SIZE, eac);
  1160.         if ((!more) && (IoErr() != ERROR_NO_MORE_ENTRIES))
  1161.         {   FreeDosObject(DOS_EXALLCONTROL, eac);
  1162.             eac = NULL;
  1163.             UnLock(DirHandle);
  1164.             DirHandle = NULL;
  1165.             rq("Can't examine path!");
  1166.         }
  1167.         if (eac->eac_Entries == 0)
  1168.         {   ; /* ExAll() failed normally with no entries */
  1169.             continue; /* more is USUALLY zero */
  1170.         }
  1171.         ead = (struct ExAllData *) EADataPtr;
  1172.  
  1173.         do
  1174.         {   /* use ead here */
  1175.  
  1176.             if (ead->ed_Type == 2) /* +2 is dir, +3 is softlink, -3 is file */
  1177.             {   size.numdirs++;    
  1178.                 if (!(size.numdirs % GRANULARITY_DIRS))
  1179.                 {   comma(size.numdirs);
  1180.                     SetGadgetAttrs
  1181.                     (   size_gadgets[GID_8_ST7], MainWindowPtr, NULL,
  1182.                         STRINGA_TextVal, commastring,
  1183.                         TAG_END
  1184.                     );
  1185.                 }
  1186.                 strcpy(tempstring, globalname);
  1187.                 if (!AddPart(tempstring, ead->ed_Name, VLONGFIELD))
  1188.                 {   FreeDosObject(DOS_EXALLCONTROL, eac);
  1189.                     eac = NULL;
  1190.                     UnLock(DirHandle);
  1191.                     DirHandle = NULL;
  1192.                     rq("Can't add filename to pathname!");
  1193.                 }
  1194.                 push(tempstring, topdir);
  1195.             } elif (ead->ed_Type == -3) // if it's a file
  1196.             {   size.numfiles++;
  1197.                 if (!(size.numfiles % GRANULARITY_FILES))
  1198.                 {   comma(size.numfiles);
  1199.                     SetGadgetAttrs
  1200.                     (   size_gadgets[GID_8_ST6], MainWindowPtr, NULL,
  1201.                         STRINGA_TextVal, commastring,
  1202.                         TAG_END
  1203.                     );
  1204.                 }
  1205.                 addduplicate(&globalname[pathlength], ead->ed_Name);
  1206.                 if (size.slack)
  1207.                 {   if (ead->ed_Size % size.blocksize == 0)
  1208.                     {   size.bytes[topdir] += (ead->ed_Size / size.blocksize) * size.blocksize;
  1209.                         size.total         += (ead->ed_Size / size.blocksize) * size.blocksize;
  1210.                     } else
  1211.                     {   size.bytes[topdir] += ((ead->ed_Size / size.blocksize) + 1) * size.blocksize;
  1212.                         size.total         += ((ead->ed_Size / size.blocksize) + 1) * size.blocksize;
  1213.                 }   }
  1214.                 else
  1215.                 {   size.bytes[topdir]     += ead->ed_Size;
  1216.                     size.total             += ead->ed_Size;
  1217.             }   }
  1218.  
  1219.             /* get next ead */
  1220.             ead = ead->ed_Next;
  1221.         } while(ead);
  1222.     } while(more);
  1223.  
  1224.     FreeDosObject(DOS_EXALLCONTROL, eac);
  1225.     // eac = NULL;
  1226.     UnLock(DirHandle);
  1227.     DirHandle = NULL;
  1228.     // don't call pop() yourself!
  1229. }
  1230.  
  1231. MODULE void pop(void)
  1232. {   ULONG breakval;
  1233.  
  1234.     pathlength = strlen(size.path);
  1235.     while (size.stackentries && status == STATUS_BUSY)
  1236.     {   size.stackentries--;
  1237.         strcpy(globalname, StackPtr[size.stackentries + 1]);
  1238.         subdir(size.topdir[size.stackentries + 1]);
  1239.         breakval = ra_checkbreak();
  1240.         if (breakval == 2)
  1241.             cleanexit(EXIT_SUCCESS);
  1242.         elif (breakval == 1)
  1243.             status = STATUS_STOPPING;
  1244. }   }
  1245. MODULE void push(STRPTR name, ULONG theindex)
  1246. {   size.stackentries++;
  1247.     if (size.stackentries == LIMIT_DIRS)
  1248.         rq("Overflow!");
  1249.     if (size.stackentries > FileNamesAllocated)
  1250.     {   if (!(StackPtr[FileNamesAllocated + 1] = AllocMem(VLONGFIELD, MEMF_PUBLIC)))
  1251.             rq("Out of memory!");
  1252.         FileNamesAllocated++;
  1253.     }
  1254.     strcpy(StackPtr[size.stackentries], name);
  1255.     size.topdir[size.stackentries] = theindex;
  1256. }
  1257.  
  1258. AGLOBAL void size_loop(ULONG gid)
  1259. {   ULONG  code;
  1260.     STRPTR stringptr;
  1261.  
  1262.     switch(gid)
  1263.     {
  1264.     case GID_8_BU1: // path ASL
  1265.         pathasl();
  1266.     break;
  1267.     case GID_8_BU3:
  1268.         asl("~(#?.info)");
  1269.         SetGadgetAttrs // `Log to file:' (string)
  1270.         (   size_gadgets[GID_8_ST2], MainWindowPtr, NULL,
  1271.             STRINGA_TextVal, size.logfile,
  1272.         TAG_END);
  1273.     break;
  1274.     case GID_8_BU4: // update
  1275.         updatesize();
  1276.     break;
  1277.     // GID_8_BU5 is stop
  1278.     case GID_8_BU6:
  1279.         root();
  1280.     break;
  1281.     case GID_8_BU7:
  1282.         parent();
  1283.     break;
  1284.     case GID_8_ST1: // path string
  1285.         if (!(GetAttr
  1286.         (   STRINGA_TextVal, size_gadgets[GID_8_ST1], (ULONG *) &stringptr
  1287.         )))
  1288.         {   rq("Unsupported inquiry!"); // should never happen
  1289.         }
  1290.         strcpy(size.path, stringptr);
  1291.         updatesize();
  1292.     break;
  1293.     case GID_8_ST2: // output string
  1294.         if (!(GetAttr
  1295.         (   STRINGA_TextVal, size_gadgets[GID_8_ST2], (ULONG *) &stringptr
  1296.         )))
  1297.         {   rq("Unsupported inquiry!"); // should never happen
  1298.         }
  1299.         strcpy(size.logfile, stringptr);
  1300.     break;
  1301.     case GID_8_CB1:
  1302.         if (!(GetAttr
  1303.         (   GA_Selected, size_gadgets[GID_8_CB1], &size.log
  1304.         )))
  1305.         {   rq("Unsupported inquiry!"); // should never happen
  1306.         }
  1307.  
  1308.         SetGadgetAttrs // `Log to file:' (string)
  1309.         (   size_gadgets[GID_8_ST2], MainWindowPtr, NULL,
  1310.             GA_Disabled, !size.log,
  1311.             TAG_END
  1312.         );
  1313.         /* For some reason, we need to explicitly refresh the string gadget
  1314.         visuals here */
  1315.         RefreshGadgets((struct Gadget *) size_gadgets[GID_8_ST2], MainWindowPtr, NULL);
  1316.  
  1317.         SetGadgetAttrs // `Log to file:' (ASL button)
  1318.         (   size_gadgets[GID_8_BU3], MainWindowPtr, NULL,
  1319.             GA_Disabled, !size.log,
  1320.             TAG_END
  1321.         );
  1322.         if (size.log)
  1323.         {   ActivateLayoutGadget(size_gadgets[GID_8_LY1], MainWindowPtr, NULL, (Object) size_gadgets[GID_8_ST2]);
  1324.         }
  1325.     break;
  1326.     case GID_8_CB2:
  1327.         if (!(GetAttr
  1328.         (   GA_Selected, size_gadgets[GID_8_CB2], (ULONG *) &size.slack
  1329.         )))
  1330.         {   rq("Unsupported inquiry!"); // should never happen
  1331.         }
  1332.     break;
  1333.     case GID_8_CB3:
  1334.         if (!(GetAttr
  1335.         (   GA_Selected, size_gadgets[GID_8_CB3], (ULONG *) &size.finddup
  1336.         )))
  1337.         {   rq("Unsupported inquiry!"); // should never happen
  1338.         }
  1339.         SetGadgetAttrs
  1340.         (   size_gadgets[GID_8_LB1], MainWindowPtr, NULL,
  1341.             GA_Disabled, !size.finddup,
  1342.             TAG_END
  1343.         );
  1344.     break;
  1345.     case GID_8_CH1:
  1346.         if (!(GetAttr
  1347.         (   CHOOSER_Selected, size_gadgets[GID_8_CH1], (ULONG *) &size.view
  1348.         )))
  1349.         {   rq("Unsupported inquiry!"); // should never happen
  1350.         }
  1351.     break;
  1352.     case GID_8_LB2:
  1353.         /* code is the position within the list, starting from 0. */
  1354.  
  1355.         if (!(GetAttr
  1356.         (   LISTBROWSER_Selected, size_gadgets[GID_8_LB2], (ULONG *) &code
  1357.         )))
  1358.         {   rq("Unsupported inquiry!"); // should never happen
  1359.         }
  1360.         code++;
  1361.         if (code <= size.entries && size.type[code] == 2)
  1362.         {   if (!(AddPart(size.path, DirNamePtr[code], VLONGFIELD + 1)))
  1363.             {   rq("Can't add filename to pathname!");
  1364.             } else
  1365.             {   updatesize();
  1366.         }   }
  1367.     break;
  1368.     default:
  1369.     break;
  1370. }   }
  1371.  
  1372. AGLOBAL void size_exit(void)
  1373. {   if (TempHandle)
  1374.     {   UnLock(TempHandle);
  1375.         TempHandle = NULL;
  1376.     }
  1377.     if (DirHandle)
  1378.     {   UnLock(DirHandle);
  1379.         DirHandle = NULL;
  1380.     }
  1381.     if (LogFileHandle)
  1382.     {   Close(LogFileHandle);
  1383.         LogFileHandle = NULL;
  1384.     }
  1385.  
  1386.     // Only call this if the list gadget is detached or not present.
  1387.     // (ie. after closewindow()).
  1388.     if (SizeNodes)
  1389.     {   clearlist(&SizeList);
  1390.         SizeNodes = FALSE;
  1391.     }
  1392.     if (DupNodes)
  1393.     {   clearreactionlist(&DupList);
  1394.         DupNodes = FALSE;
  1395.     }
  1396.     while (FileNamesAllocated)
  1397.     {   FreeMem(StackPtr[FileNamesAllocated], VLONGFIELD);
  1398.         StackPtr[FileNamesAllocated--] = NULL;
  1399.     }
  1400.     if (StackPtr)
  1401.     {   FreeVec(StackPtr);
  1402.         StackPtr = NULL;
  1403.     }
  1404.     while ( DirNamesAllocated)
  1405.     {   FreeMem(DirNamePtr[DirNamesAllocated], VLONGFIELD);
  1406.         DirNamePtr[DirNamesAllocated--] = NULL;
  1407.     }
  1408.     if (DirNamePtr)
  1409.     {   FreeVec(DirNamePtr);
  1410.         DirNamePtr = NULL;
  1411. }   }
  1412.  
  1413. AGLOBAL void size_die(void)
  1414. {   if (EmptySizeNodes)
  1415.     {   clearreactionlist(&EmptySizeList);
  1416.         EmptySizeNodes = FALSE;
  1417.     }
  1418.     if (EmptyDupNodes)
  1419.     {   clearreactionlist(&EmptyDupList);
  1420.         EmptyDupNodes = FALSE;
  1421.     }
  1422.     IOBuffer[0]  = size.log;
  1423.     IOBuffer[6]  = size.finddup;
  1424.     IOBuffer[21] = size.slack;
  1425.     IOBuffer[22] = (UBYTE) size.view;
  1426. }
  1427.  
  1428. AGLOBAL void size_config(void)
  1429. {   size.log     = (ULONG) IOBuffer[0];
  1430.     size.finddup = (ULONG) IOBuffer[6];
  1431.     size.slack   = (ULONG) IOBuffer[21];
  1432.     size.view    = (ULONG) IOBuffer[22];
  1433. }
  1434.  
  1435. MODULE void parent(void)
  1436. {   BPTR DirHandle,
  1437.          ParentHandle;
  1438.  
  1439.     if (!(DirHandle = (BPTR) Lock(size.path, ACCESS_READ)))
  1440.         rq("Can't lock directory!");
  1441.     if (!(ParentHandle = ParentDir(DirHandle)))
  1442.     {   /* It returned a NULL lock; ie. a lock on SYS:
  1443.         That is not what we want. */
  1444.         ParentHandle = DirHandle;
  1445.     }
  1446.     if (!NameFromLock(ParentHandle, size.path, VLONGFIELD))
  1447.         rq("Can't get name from lock!");
  1448.     UnLock(DirHandle);
  1449.     // DirHandle = NULL;
  1450.  
  1451.     updatesize();
  1452. }
  1453.  
  1454. MODULE void root(void)
  1455. {   BPTR  DirHandle,
  1456.           ParentHandle;
  1457.     ABOOL rootdone     = FALSE;
  1458.  
  1459.     if (!(DirHandle = (BPTR) Lock(size.path, ACCESS_READ)))
  1460.         rq("Can't lock directory!");
  1461.     do
  1462.     {   if (!(ParentHandle = ParentDir(DirHandle)))
  1463.         {   /* It returned a NULL lock; ie. a lock on SYS:
  1464.                That is not what we want. */
  1465.             ParentHandle = DirHandle;
  1466.             rootdone = TRUE;
  1467.         } else DirHandle = ParentHandle;
  1468.     } while (!rootdone);
  1469.     if (!NameFromLock(ParentHandle, size.path, VLONGFIELD))
  1470.         rq("Can't get name from lock!");
  1471.     UnLock(DirHandle);
  1472.     // DirHandle = NULL;
  1473.  
  1474.     updatesize();
  1475. }
  1476.  
  1477. MODULE void pathasl(void)
  1478. {   strcpy(asldir, size.path);
  1479.     if (dirasl()) // path for ASL must be valid?
  1480.     {   strcpy(size.path, aslresult);
  1481.         SetGadgetAttrs
  1482.         (   size_gadgets[GID_8_ST1], MainWindowPtr, NULL,
  1483.             STRINGA_TextVal, size.path,
  1484.             TAG_END
  1485.         );
  1486.         updatesize();
  1487. }   }
  1488.  
  1489. MODULE void comma(ULONG value)
  1490. {   ABOOL yes = FALSE;
  1491.  
  1492.     strcpy(commastring, " ,   ,   ,   ");
  1493.     //                    1   5   9
  1494.  
  1495.     valuestring[ 0] = '0' + (value / 1000000000);
  1496.     value %= 1000000000;
  1497.     if (valuestring[ 0] != '0')
  1498.     {   commastring[0] = valuestring[0];
  1499.         yes = TRUE;
  1500.     } else
  1501.     {   commastring[ 0] = ' ';
  1502.         commastring[ 1] = ' ';
  1503.     }
  1504.  
  1505.     valuestring[ 1] = '0' + (value /  100000000);
  1506.     value %=  100000000;
  1507.     if (yes || valuestring[1] != '0')
  1508.     {   commastring[2] = valuestring[1];
  1509.         yes = TRUE;
  1510.     } else commastring[2] = ' ';
  1511.  
  1512.     valuestring[ 2] = '0' + (value /   10000000);
  1513.     value %=   10000000;
  1514.     if (yes || valuestring[2] != '0')
  1515.     {   commastring[3] = valuestring[2];
  1516.         yes = TRUE;
  1517.     } else commastring[3] = ' ';
  1518.  
  1519.     valuestring[ 3] = '0' + (value /    1000000);
  1520.     value %=    1000000;
  1521.     if (yes || valuestring[3] != '0')
  1522.     {   commastring[4] = valuestring[3];
  1523.         yes = TRUE;
  1524.     } else
  1525.     {   commastring[4] = ' ';
  1526.         commastring[5] = ' ';
  1527.     }
  1528.  
  1529.     valuestring[ 4] = '0' + (value /     100000);
  1530.     value %=     100000;
  1531.     if (yes || valuestring[4] != '0')
  1532.     {   commastring[6] = valuestring[4];
  1533.         yes = TRUE;
  1534.     } else commastring[6] = ' ';
  1535.  
  1536.     valuestring[ 5] = '0' + (value /      10000);
  1537.     value %=      10000;
  1538.     if (yes || valuestring[5] != '0')
  1539.     {   commastring[7] = valuestring[5];
  1540.         yes = TRUE;
  1541.     } else commastring[7] = ' ';
  1542.  
  1543.     valuestring[ 6] = '0' + (value /       1000);
  1544.     value %=       1000;
  1545.     if (yes || valuestring[6] != '0')
  1546.     {   commastring[8] = valuestring[6];
  1547.         yes = TRUE;
  1548.     } else
  1549.     {   commastring[8] = ' ';
  1550.         commastring[9] = ' ';
  1551.     }
  1552.  
  1553.     valuestring[ 7] = '0' + (value /        100);
  1554.     value %=        100;
  1555.     if (yes || valuestring[7] != '0')
  1556.     {   commastring[10] = valuestring[7];
  1557.         yes = TRUE;
  1558.     } else commastring[10] = ' ';
  1559.  
  1560.     valuestring[ 8] = '0' + (value /         10);
  1561.     value %=         10;
  1562.     if (yes || valuestring[8] != '0')
  1563.     {   commastring[11] = valuestring[8];
  1564.         // yes = TRUE;
  1565.     } else commastring[11] = ' ';
  1566.  
  1567.     valuestring[ 9] = '0' +  value              ;
  1568.     commastring[12] = valuestring[9];
  1569. }
  1570.  
  1571. MODULE ABOOL dirasl(void)
  1572. {   struct FileRequester* ASLRqPtr;
  1573.     ABOOL                 success;
  1574.  
  1575.     if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, "~(#?.info)", ASL_Window, MainWindowPtr, ASL_ExtFlags1, FIL1F_NOFILES, TAG_DONE)))
  1576.     {   rq("Can't create ASL request!");
  1577.     }
  1578.     if (AslRequestTags(ASLRqPtr, ASL_Dir, asldir, ASL_Hail, "Report+ path selector", ASL_FuncFlags, FILF_PATGAD, TAG_DONE))
  1579.     {   strcpy(aslresult, ASLRqPtr->rf_Dir);
  1580.         success = TRUE;
  1581.     } else success = FALSE;
  1582.     FreeAslRequest(ASLRqPtr);
  1583.     return(success);
  1584. }
  1585.  
  1586. MODULE void showduplicates(void)
  1587. {   ABOOL                 found = FALSE,
  1588.                           started = FALSE,
  1589.                           success;
  1590.     TEXT                  pathnamestring[VLONGFIELD + 1],
  1591.                           commandstring[VLONGFIELD + 1],
  1592.                           lastfilename[VLONGFIELD + 1];
  1593.     ULONG                 breakval, i, j, k, where,
  1594.                           firstpen, secondpen, currentpen, dups;
  1595.     LONG                  length;
  1596.     STRPTR                tempPathnamePtr, tempFilenamePtr;
  1597.     struct DateTime       DateTime;
  1598.     struct FileInfoBlock* FIBPtr;
  1599.     struct Node*          ListBrowserNodePtr;
  1600.  
  1601.     DateTime.dat_Format  = FORMAT_DOS;
  1602.     DateTime.dat_Flags   = NULL;
  1603.     DateTime.dat_StrDay  = NULL;
  1604.     DateTime.dat_StrDate = datestring;
  1605.     DateTime.dat_StrTime = timestring;
  1606.  
  1607.     if (size.finddup)
  1608.     {   killduplist();
  1609.  
  1610.         lockscreen();
  1611.         firstpen = FindColor
  1612.         (   ScreenPtr->ViewPort.ColorMap,
  1613.             0xDDDDDDDD,
  1614.             0xDDDDDDDD,
  1615.             0xDDDDDDDD,
  1616.             -1
  1617.         );
  1618.         secondpen = FindColor
  1619.         (   ScreenPtr->ViewPort.ColorMap,
  1620.             0xAAAAAAAA,
  1621.             0xAAAAAAAA,
  1622.             0xAAAAAAAA,
  1623.            -1
  1624.         );
  1625.         unlockscreen();
  1626.         currentpen = firstpen;
  1627.  
  1628.         if (size.log)
  1629.         {   strcpy(logstring, "Duplicates found:\n");
  1630.             writeline();
  1631.         }
  1632.  
  1633.         /* Now we iterate through the complete file list (last entry index
  1634.         of files). For each file (i), we look at every other file (j). As
  1635.         soon as we find a matching file, we add the file (i) to the
  1636.         duplicate file list. */
  1637.  
  1638.         SetGadgetAttrs
  1639.         (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1640.             FUELGAUGE_Min,   1,
  1641.             FUELGAUGE_Max,   files,
  1642.             GA_Text,         "Matching duplicates...",
  1643.             TAG_DONE
  1644.         );
  1645.         setbar(files);
  1646.  
  1647.         for (i = 1; i <= files; i++)
  1648.         {   progressbar(i);
  1649.             breakval = ra_checkbreak();
  1650.             if (breakval == 2)
  1651.             {   cleanexit(EXIT_SUCCESS);
  1652.             } elif (breakval == 1)
  1653.             {   status = STATUS_STOPPING;
  1654.                 SetGadgetAttrs
  1655.                 (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1656.                     GA_Text, "Stopping...",
  1657.                     TAG_END
  1658.                 );
  1659.                 break;
  1660.             }
  1661.             // if the user doesn't want us to stop...
  1662.             for (j = 1; j <= files; j++)
  1663.             {   if (i != j && !stricmp(FilenamePtr[i], FilenamePtr[j]))
  1664.                 {   found = TRUE; // we found (at least one) match
  1665.                     IsDup[i] = TRUE;
  1666.                     break;
  1667.         }   }   }
  1668.  
  1669.         if (status == STATUS_BUSY)
  1670.         {   SetGadgetAttrs
  1671.             (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1672.                 FUELGAUGE_Min,   1,
  1673.                 FUELGAUGE_Max,   files,
  1674.                 GA_Text,         "Condensing duplicates...",
  1675.                 TAG_END
  1676.             );
  1677.             setbar(files);
  1678.  
  1679.             // condense list
  1680.             dups = 0;
  1681.             for (i = 1; i <= files; i++)
  1682.             {   progressbar(i);
  1683.  
  1684.                 if (IsDup[i])
  1685.                 {   dups++;
  1686.                     FilenamePtr[dups] = FilenamePtr[i];
  1687.                     PathnamePtr[dups] = PathnamePtr[i];
  1688.                     IsDup[dups]       = IsDup[i];
  1689.                 } else
  1690.                 {   FreeVec(PathnamePtr[i]);
  1691.                     FreeVec(FilenamePtr[i]);
  1692.             }   }
  1693.  
  1694.             SetGadgetAttrs
  1695.             (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1696.                 FUELGAUGE_Min,   2,
  1697.                 FUELGAUGE_Max,   dups,
  1698.                 GA_Text,         "Sorting duplicates...",
  1699.                 TAG_END
  1700.             );
  1701.             setbar(dups);
  1702.  
  1703.             // bubble sort routine
  1704.             for (i = dups; i >= 2; i--)
  1705.             {   progressbar(dups - i);
  1706.                 for (j = 2; j <= i; j++)
  1707.                 {   if (stricmp(FilenamePtr[j - 1], FilenamePtr[j]) > 0)
  1708.                     {   // swap them
  1709.                         tempPathnamePtr     = PathnamePtr[j - 1];
  1710.                         PathnamePtr[j - 1]  = PathnamePtr[j];
  1711.                         PathnamePtr[j]      = tempPathnamePtr;
  1712.                         tempFilenamePtr     = FilenamePtr[j - 1];
  1713.                         FilenamePtr[j - 1]  = FilenamePtr[j];
  1714.                         FilenamePtr[j]      = tempFilenamePtr;
  1715.             }   }   }
  1716.  
  1717.             SetGadgetAttrs
  1718.             (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1719.                 FUELGAUGE_Min,   0,
  1720.                 FUELGAUGE_Max,   dups,
  1721.                 FUELGAUGE_Level, 0,
  1722.                 GA_Text,         "Examining duplicates...",
  1723.                 TAG_END
  1724.             );
  1725.             setbar(dups);
  1726.  
  1727.             NewList(&DupList);
  1728.  
  1729.             for (i = 1; i <= dups; i++)
  1730.             {   progressbar(i);
  1731.                 breakval = ra_checkbreak();
  1732.                 if (breakval == 2)
  1733.                 {   cleanexit(EXIT_SUCCESS);
  1734.                 } elif (breakval == 1)
  1735.                 {   status = STATUS_STOPPING;
  1736.                     SetGadgetAttrs
  1737.                     (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1738.                         GA_Text,         "Stopping...",
  1739.                         TAG_END
  1740.                     );
  1741.                     break;
  1742.                 }
  1743.  
  1744.                 // begin creating the line of text
  1745.                 if (PathnamePtr[i][0] == '/')
  1746.                 {   strcpy(liststring[0], &(PathnamePtr[i][1]));
  1747.                 } else
  1748.                 {   strcpy(liststring[0], PathnamePtr[i]);
  1749.                 }
  1750.                 strcpy(logstring, " ");
  1751.                 strcat(logstring, liststring[0]);
  1752.                 if (strlen(logstring) > TRUNCATE)
  1753.                 {   *(logstring + TRUNCATE) = 0; // truncate
  1754.                 }
  1755.                 length = TRUNCATE + 2 - strlen(logstring);
  1756.                 if (length >= 1)
  1757.                 {   for (k = 1; k <= length; k++)
  1758.                     {   strcat(logstring, " ");
  1759.                 }   }
  1760.  
  1761.                 strcpy(pathnamestring, size.path);
  1762.                 if (PathnamePtr[i][0] != '/')
  1763.                 {   if (!AddPart(pathnamestring, PathnamePtr[i], 256))
  1764.                     {   rq("AddPart() failed!");
  1765.                 }   }
  1766.                 else
  1767.                 {   if (!AddPart(pathnamestring, &PathnamePtr[i][1], 256))
  1768.                     {   rq("AddPart() failed!");
  1769.                 }   }
  1770.                 success = FALSE;
  1771.  
  1772.                 // now get size and date of file
  1773.                 if (DirHandle  = (BPTR) Lock(pathnamestring, ACCESS_READ))
  1774.                 {   if (FIBPtr =        AllocDosObject(DOS_FIB, NULL))
  1775.                     {   success = TRUE;
  1776.  
  1777.                         if (Examine(DirHandle, FIBPtr))
  1778.                         {   comma(FIBPtr->fib_Size);
  1779.                             strcat(logstring, commastring);
  1780.                             for (j = 0; j <= 13; j++)
  1781.                             {   if (commastring[j] != ' ')
  1782.                                 {   where = j; // where is index of first non-space character
  1783.                                     break;
  1784.                             }   }
  1785.                             strcpy(liststring[1], &commastring[where]);
  1786.                         } else
  1787.                         {   strcpy(liststring[1], "?");
  1788.                             strcat(logstring, "            ?");
  1789.                         }
  1790.                         strcat(logstring, " ");
  1791.  
  1792.                         DateTime.dat_Stamp   = FIBPtr->fib_Date;
  1793.                         if (DateToStr(&DateTime))
  1794.                         {   strcpy(liststring[2], datestring);
  1795.                             strcpy(liststring[3], timestring);
  1796.                         } else
  1797.                         {   strcpy(liststring[2], "        ?");
  1798.                             strcpy(liststring[3], "        ?");
  1799.                         }
  1800.                         strcat(logstring, liststring[2]);
  1801.                         strcat(logstring, " ");
  1802.                         strcat(logstring, liststring[3]);
  1803.                         strcat(logstring, " ");
  1804.  
  1805.                         FreeDosObject(DOS_FIB, FIBPtr);
  1806.                         // FIBPtr = NULL;
  1807.                         UnLock(DirHandle);
  1808.                         DirHandle = NULL;
  1809.                 }   }
  1810.  
  1811.                 if (!success)
  1812.                 {   strcpy(liststring[1], "            ?");
  1813.                     strcpy(liststring[2], "            ?");
  1814.                     strcpy(liststring[3], "            ?");
  1815.                     strcat(logstring, liststring[1]);
  1816.                     strcat(logstring, " ");
  1817.                     strcat(logstring, liststring[2]);
  1818.                     strcat(logstring, " ");
  1819.                     strcat(logstring, liststring[3]);
  1820.                     strcat(logstring, " ");
  1821.                 }
  1822.  
  1823.                 getversion(pathnamestring, liststring[4]);
  1824.                 strcat(logstring, liststring[4]);
  1825.  
  1826.                 // now get the file version
  1827.                 if (ram)
  1828.                 {   strcpy(commandstring, "RAM:Version ");
  1829.                 } else
  1830.                 {   strcpy(commandstring, "Version ");
  1831.                 }
  1832.                 strcat(commandstring, pathnamestring);
  1833.                 strcat(commandstring, " >T:ReportPlus.temp");
  1834.                 if (!SystemTags(commandstring, SYS_Output, Open("NIL:", MODE_NEWFILE), TAG_DONE))
  1835.                 {   readordie("T:ReportPlus.temp");
  1836.                     for (k = 0; k <= VLONGFIELD; k++)
  1837.                     {   if (IOBuffer[k] == LF)
  1838.                         {   IOBuffer[k] = 0;
  1839.                             break;
  1840.                     }   }
  1841.                     strcpy(liststring[4], IOBuffer);
  1842.                 } else
  1843.                 {   strcpy(liststring[4], "?");
  1844.                 }
  1845.                 strcat(logstring, liststring[4]);
  1846.  
  1847.                 if (started)
  1848.                 {   if (stricmp(FilenamePtr[i], lastfilename))
  1849.                     {   if (currentpen == firstpen)
  1850.                         {   currentpen = secondpen;
  1851.                         } else currentpen = firstpen;
  1852.                 }   }
  1853.                 else started = TRUE;
  1854.  
  1855.                 if (!(ListBrowserNodePtr = AllocListBrowserNode
  1856.                 (   5,                       // columns,
  1857.                     LBNA_Column,             0,
  1858.                         LBNA_Flags,          LBFLG_CUSTOMPENS,
  1859.                         LBNCA_FGPen,         BLACK,
  1860.                         LBNCA_BGPen,         currentpen,
  1861.                         LBNCA_CopyText,      TRUE,
  1862.                         LBNCA_Text,          liststring[0],
  1863.                     LBNA_Column,             1,
  1864.                         LBNA_Flags,          LBFLG_CUSTOMPENS,
  1865.                         LBNCA_FGPen,         BLACK,
  1866.                         LBNCA_BGPen,         currentpen,
  1867.                         LBNCA_CopyText,      TRUE,
  1868.                         LBNCA_Text,          liststring[1],
  1869.                         LBNCA_Justification, LCJ_RIGHT,
  1870.                     LBNA_Column,             2,
  1871.                         LBNA_Flags,          LBFLG_CUSTOMPENS,
  1872.                         LBNCA_FGPen,         BLACK,
  1873.                         LBNCA_BGPen,         currentpen,
  1874.                         LBNCA_CopyText,      TRUE,
  1875.                         LBNCA_Text,          liststring[2],
  1876.                     LBNA_Column,             3,
  1877.                         LBNA_Flags,          LBFLG_CUSTOMPENS,
  1878.                         LBNCA_FGPen,         BLACK,
  1879.                         LBNCA_BGPen,         currentpen,
  1880.                         LBNCA_CopyText,      TRUE,
  1881.                         LBNCA_Text,          liststring[3],
  1882.                     LBNA_Column,             4,
  1883.                         LBNA_Flags,          LBFLG_CUSTOMPENS,
  1884.                         LBNCA_FGPen,         BLACK,
  1885.                         LBNCA_BGPen,         currentpen,
  1886.                         LBNCA_CopyText,      TRUE,
  1887.                         LBNCA_Text,          liststring[4],
  1888.                     TAG_END
  1889.                 )))
  1890.                 {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  1891.                 }
  1892.                 AddTail(&DupList, ListBrowserNodePtr); // AddTail() has no return code
  1893.                 DupNodes = TRUE;
  1894.                 strcpy(lastfilename, FilenamePtr[i]);
  1895.                 
  1896.                 if (size.log) // write to logfile
  1897.                 {   strcat(logstring, "\n");
  1898.                     writeline();
  1899.             }   }
  1900.             for (i = 1; i <= dups; i++)
  1901.             {   FreeVec(PathnamePtr[i]);
  1902.                 FreeVec(FilenamePtr[i]);
  1903.         }   }
  1904.         else
  1905.         {   for (i = 1; i <= files; i++)
  1906.             {   FreeVec(PathnamePtr[i]);
  1907.                 FreeVec(FilenamePtr[i]);
  1908.         }   }
  1909.  
  1910.         files = 0;
  1911.         FreeVec(IsDup);
  1912.         IsDup = NULL;
  1913.         FreeVec(PathnamePtr);
  1914.         PathnamePtr = NULL;
  1915.         FreeVec(FilenamePtr);
  1916.         FilenamePtr = NULL;
  1917.         DeleteFile("T:ReportPlus.temp"); /* returns FALSE for failure */
  1918.  
  1919.         if (size.log)
  1920.         {   if (!found)
  1921.             {   strcpy(logstring, " None\n");
  1922.             }
  1923.             strcat(logstring, "\n");
  1924.             writeline();
  1925.         }
  1926.  
  1927.         SetGadgetAttrs
  1928.         (   size_gadgets[GID_8_LB1], MainWindowPtr, NULL,
  1929.             LISTBROWSER_Labels, &DupList,
  1930.             TAG_END
  1931.         );
  1932. }   }
  1933.  
  1934. MODULE void addduplicate(STRPTR path, STRPTR filename)
  1935. {   TEXT tablestring[257];
  1936.  
  1937.     if (size.finddup)
  1938.     {   files++;
  1939.         if (files >= MAX_FILES)
  1940.         {   rq("Too many files!");
  1941.         }
  1942.         IsDup[files] = FALSE;
  1943.  
  1944.         if (!(FilenamePtr[files] = AllocVec(strlen(filename) + 1, NULL)))
  1945.         {   rq("Out of memory!");
  1946.         }
  1947.         strcpy(FilenamePtr[files], filename);
  1948.  
  1949.         strcpy(tablestring, path);
  1950.         if (!AddPart(tablestring, filename, 256))
  1951.         {   rq("AddPart() failed!");
  1952.         }
  1953.         if (!(PathnamePtr[files] = AllocVec(strlen(tablestring) + 1, NULL)))
  1954.         {   rq("Out of memory!");
  1955.         }
  1956.         strcpy(PathnamePtr[files], tablestring);
  1957.  
  1958.     /* size.path   path           filename    PathnamePtr[]           FilenamePtr[]
  1959.        "SYS:Tools" "Commodities/" "AutoPoint" "Commodities/AutoPoint" "AutoPoint" */
  1960. }   }
  1961.  
  1962. MODULE void writeline(void)
  1963. {   /* The file is opened just before the first call to writeline()
  1964.     (when the date, time, etc. is written). Then we keep the file open
  1965.     and do our scan. Then we write out the results a line at a time,
  1966.     then the free and total bytes.
  1967.       If we are also doing duplicates, we now do our thinking,
  1968.     write the results a line at a time, then close the file. */
  1969.  
  1970.     if (FPuts(LogFileHandle, logstring))
  1971.     {   Close(LogFileHandle);
  1972.         LogFileHandle = NULL;
  1973.         rq("Can't append to file!");
  1974. }   }
  1975.  
  1976. MODULE void killsizelist(void)
  1977. {   SetGadgetAttrs
  1978.     (   size_gadgets[GID_8_LB2], MainWindowPtr, NULL,
  1979.         LISTBROWSER_Labels, &EmptySizeList,
  1980.         TAG_END
  1981.     );
  1982.     if (SizeNodes)
  1983.     {   clearreactionlist(&SizeList);
  1984.         SizeNodes = FALSE;
  1985. }   }
  1986.  
  1987. MODULE void killduplist(void)
  1988. {   SetGadgetAttrs
  1989.     (   size_gadgets[GID_8_LB1], MainWindowPtr, NULL,
  1990.         LISTBROWSER_Labels, &EmptyDupList,
  1991.         TAG_END
  1992.     );
  1993.     if (DupNodes)
  1994.     {   clearreactionlist(&DupList);
  1995.         DupNodes = FALSE;
  1996. }   }
  1997.  
  1998. AGLOBAL ULONG Hook8Func(struct Hook *h, VOID *o, VOID *msg)
  1999. {   /* "When the hook is called, the data argument points to the
  2000.     window object and message argument to the IntuiMessage." */
  2001.  
  2002.     UWORD code, qual;
  2003.     ULONG scroll;
  2004.  
  2005.     geta4(); // wait till here before doing anything
  2006.     code = ((struct IntuiMessage *) msg)->Code;
  2007.     qual = ((struct IntuiMessage *) msg)->Qualifier;
  2008.     switch(code)
  2009.     {
  2010.     case SCAN_HELP:
  2011.         if (status == STATUS_READY)
  2012.         {   helpabout();
  2013.         }
  2014.     break;
  2015.     case SCAN_ESCAPE:
  2016.         if (status == STATUS_READY)
  2017.         {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  2018.             {   cleanexit(EXIT_SUCCESS);
  2019.             } else page = 0;
  2020.         } else
  2021.         {   // assert(status == STATUS_BUSY);
  2022.             status = STATUS_STOPPING;
  2023.         }
  2024.     break;
  2025.     case SCAN_P:
  2026.         ActivateLayoutGadget(size_gadgets[GID_8_LY1], MainWindowPtr, NULL, (Object) size_gadgets[GID_8_ST1]);
  2027.     break;
  2028.     case SCAN_V:
  2029.         if (status == STATUS_READY)
  2030.         {   if (!(qual & IEQUALIFIER_LSHIFT) && !(qual & IEQUALIFIER_RSHIFT))
  2031.             {   if (size.view < UNITOPTIONS)
  2032.                     size.view++;
  2033.                 else size.view = 0;
  2034.             } else
  2035.             {   if (size.view > 0)
  2036.                     size.view--;
  2037.                 else size.view = UNITOPTIONS;
  2038.             }
  2039.             SetGadgetAttrs
  2040.             (   size_gadgets[GID_8_CH1], MainWindowPtr, NULL,
  2041.                 CHOOSER_Selected, size.view,
  2042.                 TAG_END
  2043.             );
  2044.         }
  2045.     break;
  2046.     case SCAN_PERIOD:
  2047.         pathasl();
  2048.     break;
  2049.     case SCAN_UP:
  2050.         if (qual & IEQUALIFIER_CONTROL)
  2051.         {   scroll = LBP_TOP;
  2052.         } elif (qual & IEQUALIFIER_LSHIFT || qual & IEQUALIFIER_RSHIFT)
  2053.         {   scroll = LBP_PAGEUP;
  2054.         } else scroll = LBP_LINEUP;
  2055.     break;
  2056.     case SCAN_DOWN:
  2057.         if (qual & IEQUALIFIER_CONTROL)
  2058.         {   scroll = LBP_BOTTOM;
  2059.         } elif (qual & IEQUALIFIER_LSHIFT || qual & IEQUALIFIER_RSHIFT)
  2060.         {   scroll = LBP_PAGEDOWN;
  2061.         } else scroll = LBP_LINEDOWN;
  2062.     break;
  2063.     default:
  2064.     break;
  2065.     }
  2066.  
  2067.     if (code == SCAN_UP || code == SCAN_DOWN)
  2068.     {   SetGadgetAttrs
  2069.         (   size_gadgets[GID_8_LB2],      // pointer to gadget
  2070.             MainWindowPtr,                // pointer to window (not window object!)
  2071.             NULL,                         // pointer to requester
  2072.             LISTBROWSER_Position, scroll, // tags
  2073.             TAG_DONE                      // done
  2074.         );
  2075.     }
  2076.  
  2077.     return(1);
  2078. }
  2079.  
  2080. MODULE void ghost(void)
  2081. {   status = STATUS_BUSY;
  2082.  
  2083.     SetGadgetAttrs // "update"
  2084.     (   size_gadgets[GID_8_BU4], MainWindowPtr, NULL,
  2085.         GA_Disabled, TRUE,
  2086.         TAG_END
  2087.     );
  2088.     SetGadgetAttrs // "stop"
  2089.     (   size_gadgets[GID_8_BU5], MainWindowPtr, NULL,
  2090.         GA_Disabled, FALSE,
  2091.         TAG_END
  2092.     );
  2093. }
  2094.  
  2095. MODULE void unghost(void)
  2096. {   status = STATUS_READY;
  2097.  
  2098.     SetGadgetAttrs // "update"
  2099.     (   size_gadgets[GID_8_BU4], MainWindowPtr, NULL,
  2100.         GA_Disabled, FALSE,
  2101.         TAG_END
  2102.     );
  2103.     SetGadgetAttrs // "stop"
  2104.     (   size_gadgets[GID_8_BU5], MainWindowPtr, NULL,
  2105.         GA_Disabled, TRUE,
  2106.         TAG_END
  2107.     );
  2108. }
  2109.  
  2110. MODULE void scale(ULONG bytes)
  2111. {   if (size.view == 0) // bytes
  2112.     {   comma(bytes);
  2113.     } elif (size.view == 1) // kilobytes
  2114.     {   comma(bytes / 1024);
  2115.     } elif (size.view == 2) // megabytes
  2116.     {   comma(bytes / 1048576);
  2117.     } else
  2118.     {   // assert(size.view == 3); // blocks
  2119.         // assert(size.blocksize); // to avoid division by zero
  2120.         comma(bytes / size.blocksize);
  2121.         if (bytes % size.blocksize)
  2122.         {   comma((bytes / size.blocksize) + 1);
  2123.         } else // exactly on a block boundary
  2124.         {   comma(bytes / size.blocksize);
  2125. }   }   }
  2126.  
  2127. MODULE void __inline progressbar(ULONG level)
  2128. {   if (!(level % increment))
  2129.     {   SetGadgetAttrs
  2130.         (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  2131.             FUELGAUGE_Level, level,
  2132.             TAG_END
  2133.         );
  2134. }   }
  2135.  
  2136.